use super::size::*;

#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub struct Position {
    pub size: Size,
    x: usize,
    y: usize,
}

impl Position {
    pub fn new(size: Size, x: usize, y: usize) -> Self {
        Position { size, x, y }
    }

    pub fn x(&self) -> usize {
        self.x
    }

    pub fn y(&self) -> usize {
        self.y
    }

    pub fn index(&self) -> usize {
        self.y * self.size.width + self.x
    }

    pub fn next(&self) -> Option<Self> {
        let new_x = self.x() + 1;
        if new_x >= self.size.width {
            let new_y = self.y() + 1;
            if new_y >= self.size.height {
                None
            } else {
                Some(Position::new(self.size, 0, self.y + 1))
            }
        } else {
            Some(Position::new(self.size, new_x, self.y))
        }
    }
}

pub struct PositionsOfSizeIterator {
    position: Option<Position>,
}

impl Iterator for PositionsOfSizeIterator {
    type Item = Position;

    fn next(&mut self) -> Option<Self::Item> {
        match self.position {
            Some(pos) => {
                self.position = pos.next();
                Some(pos)
            }
            None => None,
        }
    }
}

impl Size {
    pub fn iter_positions(&self) -> PositionsOfSizeIterator {
        PositionsOfSizeIterator {
            position: Option::Some(Position::new(*self, 0, 0)),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_positions_of_size_iterator() {
        let size = size(3, 3);

        let count = size.iter_positions().count();

        assert_eq!(9, count);
    }
}
